//!
/**
***********************************************************************************************************
* <sdkmesh_reader Implementation>
***********************************************************************************************************
* @file sdkmesh_reader.cpp
***********************************************************************************************************/

/***********************************************************************************************************
* Includes
***********************************************************************************************************/
#include "sdkmesh_reader.h"

#include "windows.h"
#include "d3d9.h"
#include "d3d11.h"
#include "d3dx9math.h"
#include "dxut/SDKmesh.h"

#include "RBD3D11Renderer.h"
#include "RBD3D11HardwareBufferManager.h"

#include "RBMain/RBEntity.h"
#include "RBMain/RBGeometry.h"
#include "RBTransformSystem/RBTransformComponent.h"


sdkmesh_reader::sdkmesh_reader()
{

}

sdkmesh_reader::~sdkmesh_reader()
{

}

std::vector<ID3D11ShaderResourceView*> rsc_views;
std::vector<ID3D11Buffer*> vertex_buffers;
std::vector<ID3D11Buffer*> index_buffers;

void CALLBACK create_texture( ID3D11Device* pDev, char* szFileName,
                     ID3D11ShaderResourceView** ppRV, void* pContext )
{
    RBD3D11HardwareBufferManager::create_texture(pDev, szFileName, ppRV);
}

void CALLBACK create_vb( ID3D11Device* pDev, ID3D11Buffer** ppBuffer,
                         D3D11_BUFFER_DESC BufferDesc, void* pData, void* pContext )
{
    RBD3D11HardwareBufferManager::create_buffer(pDev, ppBuffer, &BufferDesc, pData);
}
void CALLBACK create_ib( ID3D11Device* pDev, ID3D11Buffer** ppBuffer,
                         D3D11_BUFFER_DESC BufferDesc, void* pData, void* pContext )
{
    RBD3D11HardwareBufferManager::create_buffer(pDev, ppBuffer, &BufferDesc, pData);

}

RBStream* sdkmesh_reader::Load( const RBString& strFilename )
{
    CDXUTSDKMesh d3d_mesh;
    SDKMESH_CALLBACKS11 callbacks;
    callbacks.pContext = m_renderer;
    callbacks.pCreateIndexBuffer = create_ib;
    callbacks.pCreateVertexBuffer = create_vb;
    callbacks.pCreateTextureFromFile = create_texture;

    WCHAR path[_MAX_PATH];
    size_t converted_chars;
    mbstowcs_s(&converted_chars, path, _MAX_PATH, strFilename.c_str(), strFilename.size());

    if ( FAILED(d3d_mesh.Create(RBD3D11Renderer::GetSingleton()->GetDevice(), path, false, &callbacks)) )
    {
        return NULL;
    }
    
    RBEntityHandle entity = RBEntity::CreateEntity();
    UINT bone_count = d3d_mesh.GetNumFrames();
    RBTransformComponentHandle* xforms = new RBTransformComponentHandle[bone_count];
    RBTransformComponent::Create(entity, xforms, bone_count);

    for (uint32 bone_idx = 0; bone_idx < bone_count; ++bone_idx)
    {
        SDKMESH_FRAME* d3d_bone = d3d_mesh.GetFrame(bone_idx);
        if (d3d_bone->ParentFrame != -1)
        {
            xforms[d3d_bone->ParentFrame]->AddChild((uint16)bone_idx);
        }

    }

    std::vector<RBVertexBuffer*> vbs;
    uint32 vb_count = d3d_mesh.GetNumVBs();
    for (uint32 ui=0; ui < vb_count; ++ui)
    {
        vbs.push_back(RBD3D11HardwareBufferManager::create_vb_from_d3d(d3d_mesh.GetVB11At(ui)));
    }

    std::vector<RBVertexBuffer*> ibs;
    uint32 ib_count = d3d_mesh.GetNumIBs();
    for (uint32 ui=0; ui < vb_count; ++ui)
    {
        ibs.push_back(RBD3D11HardwareBufferManager::create_ib_from_d3d(d3d_mesh.GetIB11At(ui)));

    }

    UINT mesh_count = d3d_mesh.GetNumMeshes();
    for (UINT mesh_idx = 0; mesh_idx < mesh_count; ++mesh_idx)
    {
        SDKMESH_MESH* mesh = d3d_mesh.GetMesh(mesh_idx);
        UINT geom_count = d3d_mesh.GetNumSubsets(mesh_idx);
        RBGeometry::Create(entity, xforms[mesh->pFrameInfluences[0]]);
        for (UINT geom_idx=0; geom_idx < geom_count; ++geom_idx)
        {
            SDKMESH_SUBSET* mesh_subset = d3d_mesh.GetSubset(mesh_idx, geom_idx);
        }
    }
    delete[] xforms;

    RBStream* stream = new RBStream;
    stream->Insert(entity);

    return stream;
}
